/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.nViron.Tiles;

import instar.dg.Debug.Debug;
import instar.dg.Packets.Channel;
import instar.dg.Tiles.Tile;
import instar.dg.Tiles.TilesCache;
import instar.dg.util.TaskQueue;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.nViron.Graffiti.GraffitiClient;

/**
 *
 * @author stefan
 */
public class TilesCacheSE extends TilesCache {

    protected static final String FILE_EXTENSION = ".tile";
    protected TaskQueue taskIOQueue = new TaskQueue();
    protected String cacheDirectory;

    /**
     *
     * @deprecated 
     */
    protected TilesCacheSE(instar.dg.Packets.Channel channel, String cacheDir) throws Exception {
        super(channel);

        cacheDirectory = cacheDir;
        if (!cacheDirectory.endsWith("/")) {
            cacheDirectory += "/";
        }
        checkDir();
    }

    protected TilesCacheSE(String serverIP, int port, String cacheDir) throws Exception {
        super(serverIP, port);

        cacheDirectory = cacheDir;
        if (!cacheDirectory.endsWith("/")) {
            cacheDirectory += "/";
        }
        checkDir();
    }

    protected void checkDir() throws Exception {

        File fconn = new File(cacheDirectory);
        if (!fconn.exists() && (!fconn.mkdir() || !fconn.setReadable(true) || !fconn.setWritable(true))) {
            throw new Exception("checkDir failed ");
        }


    }

    /**
     * @deprecated 
     */
    public final static void init(instar.dg.Packets.Channel channel, String cacheDir) throws Exception {
        instance = new TilesCacheSE(channel, cacheDir);
    }

    public static final void init(String serverIP, int port, String cacheDir) throws Exception {
        instance = new TilesCacheSE(serverIP, port, cacheDir);
    }

    @Override
    protected boolean alreadyLoaded(long mapId, int x, int y) {
        boolean ret = false;
        String filename = cacheDirectory + getFilename(mapId, x, y);
        try {
            File fconn = new File(filename);
            ret = fconn.exists();
        } catch (Throwable t) {
            Debug.out.println(System.currentTimeMillis() + " ms - [" + Thread.currentThread().getName() + "] TilesCacheME.alreadyLoaded('" + filename + "') throws " + t.toString());
            t.printStackTrace();
        }
        return ret;
    }

    private final String getFilename(long mapId, int x, int y) {
        return "T" + mapId + "_" + x + "_" + y + FILE_EXTENSION;
    }

    @Override
    protected void loadTile(final long mapId, final int x, final int y) {
        taskIOQueue.addTask(new Runnable() {

            @Override
            public void run() {
                String filename = cacheDirectory + getFilename(mapId, x, y);
                long begin = System.currentTimeMillis();
                try {
                    File fconn = new File(filename);
                    if (fconn.exists() && (fconn.length() > 0)) {
                        FileInputStream is = new FileInputStream(fconn);
                        DataInputStream dis = new DataInputStream(is);

                        TileSE tile = new TileSE();
                        tile.readFromDataInput(dis);
                        // TODO: does compiler/rt optimizes this line and removes it??? -> explizit create image!!!
                        //tile.getImage();
                        TilesCache.invokeTileLoaded(tile);
                        dis.close();
                        is.close();
                        dis = null;
                    }
                    fconn = null;
                    Debug.out.println(System.currentTimeMillis() + " ms - [" + Thread.currentThread().getName() + "] TilesCacheME.loadTile('" + filename + "') ends in " + (System.currentTimeMillis() - begin) + " ms.");
                } catch (Throwable t) {
                    Debug.out.println(System.currentTimeMillis() + " ms - [" + Thread.currentThread().getName() + "] TilesCacheME.loadTile('" + filename + "') throws " + t.toString());
                    t.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void saveTile(final Tile tile) {
        taskIOQueue.addTask(new Runnable() {

            @Override
            public void run() {
                String filename = cacheDirectory + getFilename(tile.getMapId(), tile.getTileX(), tile.getTileY());
                long begin = System.currentTimeMillis();
//                Debug.out.println(System.currentTimeMillis() + " ms - [" + Thread.currentThread().getName() + "] TilesCacheSE.saveTile('" + filename + "')");
                try {
                    File fconn = new File(filename);

                    if (fconn.exists()) {
                        fconn.delete();
                    }
                    fconn.createNewFile();
                    FileOutputStream os = new FileOutputStream(fconn);
                    DataOutputStream dos = new DataOutputStream(os);
                    tile.appendToDataOutput(dos);
                    dos.close();
                    os.close();

                } catch (Throwable t) {
                    Debug.out.println(System.currentTimeMillis() + " ms - [" + Thread.currentThread().getName() + "] TilesCacheME.saveTile('" + filename + "') throws " + t.toString());
                    t.printStackTrace();
                }
                Debug.out.println(System.currentTimeMillis() + " ms - [" + Thread.currentThread().getName() + "] TilesCacheME.saveTile('" + filename + "') ends in " + (System.currentTimeMillis() - begin) + " ms.");
            }
        });
    }

    @Override
    public Channel openChannel() throws IOException {

        Channel channel = null;
        try {
            Socket sock = new java.net.Socket(serverIP, port);
            sock.setSoLinger(true, 5);
            sock.setKeepAlive(true);

            channel = new Channel(sock.getInputStream(), sock.getOutputStream());
        } catch (UnknownHostException ex) {
            Logger.getLogger(GraffitiClient.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        } catch (IOException ex) {
            Logger.getLogger(GraffitiClient.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
        return channel;
    }
}
